//
// Created by lihengliu on 2023/3/3.
//

#ifndef JNIDEMO_JNI_NUMBER_UTIL_H
#define JNIDEMO_JNI_NUMBER_UTIL_H
#include <jni.h>
#include <typeinfo>

const char *numberTypeNames[] = {
        typeid(char).name(),
        typeid(bool).name(),
        typeid(int).name(),
        typeid(short).name(),
        typeid(float).name(),
        typeid(long).name(),
        typeid(double).name(),
};

const char *numberClassNames[] = {
        "java/lang/Character",
        "java/lang/Boolean",
        "java/lang/Integer",
        "java/lang/Short",
        "java/lang/Float",
        "java/lang/Long",
        "java/lang/Double",
};

const char *numberConstructorNames[] = {
        "(C)V",
        "(Z)V",
        "(I)V",
        "(S)V",
        "(F)V",
        "(J)V",
        "(D)V",
};

const char *numberConstructorNoParamNames[] = {
        "()C",
        "()Z",
        "()I",
        "()S",
        "()F",
        "()J",
        "()D",
};

const char *numberValueMethodNames[] = {
        "charValue",
        "booleanValue",
        "intValue",
        "shortValue",
        "floatValue",
        "longValue",
        "doubleValue",
};

template<class T> class JNINumberUtil {
  public:
    jint findIndex(const char *name, const char* class_names[]) {
        jint result = -1;
        jint length = sizeof(class_names);
        for (int i = 0; i < length; ++i) {
            if (name == class_names[i]) {
                result = i;
                break;
            }
        }
        return result;
    }

    jclass createClass(JNIEnv *env) {
        jclass clazz = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            clazz = env->FindClass(numberClassNames[index]);
        }
        return clazz;
    }

    //创建实例
    jobject createInstance(JNIEnv *env) {
        jclass clazz = createClass(env);
        jobject obj = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            jmethodID init_method = env->GetMethodID(clazz, "<init>", numberConstructorNames[index]);
            obj = env->NewObject(clazz, init_method);
        }
        return obj;
    }

    //创建实例
    jobject createInstance(JNIEnv *env, jclass clazz) {
        jobject obj = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            jmethodID init_method = env->GetMethodID(clazz, "<init>", numberConstructorNames[index]);
            obj = env->NewObject(clazz, init_method);
        }
        return obj;
    }

    //创建构造方法
    jmethodID createConstructor(JNIEnv *env) {
        jclass clazz = createClass(env);
        jmethodID _method = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            _method = env->GetMethodID(clazz, "<init>", numberConstructorNames[index]);;
        }
        return _method;
    }

    //创建构造方法
    jmethodID createConstructor(JNIEnv *env,jclass clazz) {
        jmethodID _method = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            _method = env->GetMethodID(clazz, "<init>", numberConstructorNames[index]);;
        }
        return _method;
    }

    //创建值方法
    jmethodID createValueMethod(JNIEnv *env) {
        jclass clazz = createClass(env);
        jmethodID _method = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            _method = env->GetMethodID(clazz, numberValueMethodNames[index], numberConstructorNoParamNames[index]);
        }
        return _method;
    }

    //创建值方法
    jmethodID createValueMethod(JNIEnv *env, jclass clazz) {
        jmethodID _method = nullptr;
        int index = findIndex(typeid(T).name(), numberTypeNames);
        if (index != -1) {
            _method = env->GetMethodID(clazz, numberValueMethodNames[index], numberConstructorNoParamNames[index]);
        }
        return _method;
    }

    JNINumberUtil<T>(){}
    ~JNINumberUtil<T>(){}
};
#endif //JNIDEMO_JNI_NUMBER_UTIL_H
